package com.abing.starry.spi.monitor;

import com.abing.starry.spi.monitor.model.CpuInfo;
import com.abing.starry.spi.monitor.model.DiskInfo;
import com.abing.starry.spi.monitor.model.MemoryInfo;
import com.abing.starry.spi.monitor.model.SystemInfo;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;

/**
 * @Author CaptainBing
 * @Date 2024/9/25 16:22
 * @Description
 */
@Component
public class SystemMonitorServiceImpl implements SystemMonitorService{

    private final static MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
    private final static int MB = 1024 * 1024;

    @Override
    public Mono<SystemInfo> system() {
        return Mono
                .zip(
                        cpu(),
                        memory(),
                        disk()
                )
                .map(tp3 -> SystemInfo.of(tp3.getT1(), tp3.getT2(), tp3.getT3()));
    }

    @Override
    public Mono<MemoryInfo> memory() {
        return Mono.fromSupplier(() -> {
            MemoryInfo info = new MemoryInfo();
            info.setSystemTotal((long) SystemMonitor.totalSystemMemory.value());
            info.setSystemFree((long) SystemMonitor.freeSystemMemory.value());

            MemoryUsage heap = memoryMXBean.getHeapMemoryUsage();
            MemoryUsage nonHeap = memoryMXBean.getNonHeapMemoryUsage();
            long nonHeapMax = (nonHeap.getMax() > 0 ? nonHeap.getMax() / MB : info.getSystemTotal());

            info.setJvmHeapFree((heap.getMax() - heap.getUsed()) / MB);
            info.setJvmHeapTotal(heap.getMax() / MB);

            info.setJvmNonHeapFree(nonHeapMax - nonHeap.getUsed() / MB);
            info.setJvmNonHeapTotal(nonHeapMax);
            return info;
        });
    }

    @Override
    public Mono<CpuInfo> cpu() {
        return Mono.fromSupplier(() -> {
            CpuInfo info = new CpuInfo();

            info.setSystemUsage((float) (SystemMonitor.systemCpuUsage.value()));
            info.setJvmUsage((float) (SystemMonitor.jvmCpuUsage.value()));

            return info;
        });
    }

    @Override
    public Mono<DiskInfo> disk() {
        return Mono.fromSupplier(() -> {
            long total = 0, usable = 0;
            for (File file : File.listRoots()) {
                total += file.getTotalSpace();
                usable += file.getUsableSpace();
            }
            DiskInfo diskInfo = new DiskInfo();
            diskInfo.setTotal(total / MB);
            diskInfo.setFree(usable / MB);
            return diskInfo;
        });
    }
}
